package pack;


import io.PacketParser;

import java.io.IOException;
import java.util.Vector;

import model.Player;
import net.ChannelListener;
import util.Logger;

public final class World implements Runnable {
    public Object LOCK = new Object();
    private Vector<model.Player> players = new Vector<Player>();
    private int id;
    private ChannelListener channelListener;

    @SuppressWarnings("unchecked")
    public World(int id, String host) {
        try {
            channelListener = new ChannelListener(this, host);
        } catch (IOException ioe) {
            util.Logger.println("World " + id + " unable to run on host " + host + ": " + ioe.getMessage());
            return;
        }
        this.id = id;
        Engine.newThread(this);
    }

    public int id() {
        return id;
    }

    public Vector<model.Player> players() {
        return players;
    }

    public int getFreePlayerId() {
        for (int id = 1; id < 2048; id++) {
            boolean failed = false;
            for (Player p : players) {
                if (p.id() == id) {
                    failed = true;
                    break;
                }
            }
            if (!failed) {
                return id;
            }
        }
        return -1;
    }

    @Override
    public void run() {
        while (true) {
            long cycleStart = System.currentTimeMillis();
            synchronized (LOCK) {
                try {
                    for (Player p : players) {
                        PacketParser.parsePlayerPackets(p);
                    }
                    for (Player p : players) {
                        p.tick();
                    }
                    for (Player p : players) {
                        p.actionSender().update();
                    }
                    for (Player p : players) {
                        p.clearUpdates();
                    }
                    for (Player p : players) {
                        ChannelListener.write(p);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            int nextCycle = 600 - (int) (System.currentTimeMillis() - cycleStart);
            if (nextCycle < 0) {
                nextCycle = 1;
            } else if (nextCycle > 600) {
                nextCycle = 600;
            }
            try {
                Thread.sleep(nextCycle);
            } catch (InterruptedException ie) {
                break;
            }
        }
        Logger.println("World " + id + " has shutdown");
    }

    @Override
    public String toString() {
        return "[" + id + "] World";
    }
}